﻿#include "discrete_face_loop.hxx"
#define LEFT 0
#define RIGHT 1
// #define DEBUG

auto LoopProcessor::GetPPointsFromCoedge(COEDGE* coedge) {
    struct Result {
        PPointPtr start;
        PPointPtr end;
        bool has_singular{ false };
    };
    int nP = 0;
    bool has_singular{ false };
    SPAposition* polyline;
    double* params;
    PPointPtr begin, last_point;
    get_facet_edge_points_and_params(coedge->edge(), polyline, params, nP);  // params是edge的param，但是pcurve的param可能会跟edge在正负域上镜像
    PCURVE* pc = coedge->geometry();
    REVBIT r = coedge->sense();
    REVBIT need_rev = coedge->sense() ^ info_.sense ^ info_.surf.left_handed_uv();
    if (need_rev) {
        std::reverse(polyline, polyline + nP);
        std::reverse(params, params + nP);
    }
    //
    SPApar_pos param;
    SPApar_pos prev_param;
    SPAposition prev_pos_3d;
    for (int i = 0; i < nP; i++) {
        double t = r ? -params[i] : params[i];
        if (pc == nullptr) {
            param = begin == nullptr ? info_.surf.param(polyline[i]) : info_.surf.param(polyline[i], prev_param);  // 通过添加前一个点的参数值作为参考点，加速投影
        }
        else {
            param = pc->equation().eval_position(polyline[i], r ? -params[i] : params[i], true);  // 设计上sense仅反转了正负域
        }
        boundary_analyzer_.GetFitParam(param);
        if (last_point && prev_param == param) {
            continue;
        }
        prev_param = param;
        if (last_point == nullptr) {
            begin = std::make_shared<PPoint>(param);
            last_point = begin;
            ppoint_set_.insert(last_point);
            prev_pos_3d = polyline[i];
        }
        else if (boundary_analyzer_.IsSingular(param) || !same_point(prev_pos_3d, polyline[i])) {
            auto singular_type = boundary_analyzer_.GetSingularType(param);
            if (singular_type != bndy_unknown) {
                has_singular = true;
            }
            prev_pos_3d = polyline[i];
            PPointPtr new_ppoint = std::make_shared<PPoint>(param);
            ppoint_set_.insert(new_ppoint);
            last_point->SetNext(new_ppoint);
            last_point = new_ppoint;
        }
    }
    return Result{ begin, last_point, has_singular };
}

PPointPtr LoopProcessor::PPointsFilter(PPointPtr start) {
    PPointPtr curr = start;
    PPointPtr next;
    do {
        next = curr->GetNext();
        auto spl = (spline*)&info_.surf;
        if (curr->pos == next->pos || boundary_analyzer_.SamePointJudgeBy3D(curr->pos, next->pos)) {
            curr->SetNext(next->GetNext());
            if (next == start) start = next->GetNext();
            ppoint_set_.erase(next);
            continue;
        }
        curr = next;
    } while (curr != nullptr && curr != start && curr->GetNext() != nullptr);
    return start;
}

PPointPtr LoopProcessor::PPointsFixer(PPointPtr start) {
    PPointPtr curr = start;
    PPointPtr next;
    do {
        next = curr->GetNext();
        // SamePoint的判断是否需要添加?
        double curr_cord, next_cord;
        if (info_.is_periodic_u) {
            if (boundary_analyzer_.IsOnBoundary<ParamDirect::U>(curr->pos) && boundary_analyzer_.IsOnBoundary<ParamDirect::U>(next->pos)) {
                curr_cord = curr->pos.v;
                next_cord = next->pos.v;
                if (info_.is_periodic_v && boundary_analyzer_.IsOnBoundary<ParamDirect::V>(curr->pos)) {  // 双周期判断
                    curr_cord = boundary_analyzer_.GetClosestPoint(next->pos, curr->pos).v;
                }
                if (info_.is_periodic_v && boundary_analyzer_.IsOnBoundary<ParamDirect::V>(next->pos)) {
                    next_cord = boundary_analyzer_.GetClosestPoint(curr->pos, next->pos).v;
                }
                if (curr_cord > next_cord) {
                    curr->pos.u = next->pos.u = info_.u_le;
                }
                else {
                    curr->pos.u = next->pos.u = info_.u_ri;
                }
            }
        }
        if (info_.is_periodic_v) {
            if (boundary_analyzer_.IsOnBoundary<ParamDirect::V>(curr->pos) && boundary_analyzer_.IsOnBoundary<ParamDirect::V>(next->pos)) {
                curr_cord = curr->pos.u;
                next_cord = next->pos.u;
                if (info_.is_periodic_u && boundary_analyzer_.IsOnBoundary<ParamDirect::U>(curr->pos)) {
                    curr_cord = boundary_analyzer_.GetClosestPoint(next->pos, curr->pos).u;
                }
                if (info_.is_periodic_u && boundary_analyzer_.IsOnBoundary<ParamDirect::U>(next->pos)) {
                    next_cord = boundary_analyzer_.GetClosestPoint(curr->pos, next->pos).u;
                }
                if (curr_cord < next_cord) {
                    curr->pos.v = next->pos.v = info_.v_le;
                }
                else {
                    curr->pos.v = next->pos.v = info_.v_ri;
                }
            }
        }
        curr->dir = boundary_analyzer_.GetClosestPoint(curr->pos, next->pos) - curr->pos;
        curr = next;
    } while (curr != nullptr && curr != start && curr->GetNext() != nullptr);
    return start;
}

template <ParamDirect X> void LoopProcessor::HandleCrossSingularPoint(PPointPtr prev, PPointPtr curr, PPointPtr next) {
    PPointPtr first_singuar_point = curr;
    PPointPtr second_singuar_point = std::make_shared<PPoint>(*curr);
    ppoint_set_.insert(second_singuar_point);
    if constexpr (X == ParamDirect::U) {
        first_singuar_point->pos.v = prev->pos.v;
        second_singuar_point->pos.v = next->pos.v;
    }
    else {
        first_singuar_point->pos.u = prev->pos.u;
        second_singuar_point->pos.u = next->pos.u;
    }
    PPointPtr first_singuar_point_next = std::make_shared<PPoint>(*first_singuar_point);
    PPointPtr second_singuar_point_next = std::make_shared<PPoint>(*second_singuar_point);
    ppoint_set_.insert(first_singuar_point_next);
    ppoint_set_.insert(second_singuar_point_next);
    first_singuar_point->SetNext(first_singuar_point_next);
    first_singuar_point_next->SetNext(nullptr);
    second_singuar_point_next->SetNext(second_singuar_point);
    second_singuar_point->SetNext(next);

    if constexpr (X == ParamDirect::U) {
        if (prev->pos.v < next->pos.v) {
            first_singuar_point_next->pos.v = info_.v_le;
            second_singuar_point_next->pos.v = info_.v_ri;
            period_edge_v[LEFT][first_singuar_point_next->pos.u].push_back(std::make_pair(first_singuar_point_next, Direct::right));
            period_edge_v[RIGHT][second_singuar_point_next->pos.u].push_back(std::make_pair(second_singuar_point_next, Direct::right));
        }
        else {
            first_singuar_point_next->pos.v = info_.v_ri;
            second_singuar_point_next->pos.v = info_.v_le;
            period_edge_v[RIGHT][first_singuar_point_next->pos.u].push_back(std::make_pair(first_singuar_point_next, Direct::left));
            period_edge_v[LEFT][second_singuar_point_next->pos.u].push_back(std::make_pair(second_singuar_point_next, Direct::left));
        }
    }
    else {
        if (prev->pos.u < next->pos.u) {
            first_singuar_point_next->pos.u = info_.u_le;
            second_singuar_point_next->pos.u = info_.u_ri;
            period_edge_u[RIGHT][first_singuar_point_next->pos.v].push_back(std::make_pair(first_singuar_point_next, Direct::left));
            period_edge_u[LEFT][second_singuar_point_next->pos.v].push_back(std::make_pair(second_singuar_point_next, Direct::left));

        }
        else {
            first_singuar_point_next->pos.u = info_.u_ri;
            second_singuar_point_next->pos.u = info_.u_le;
            period_edge_u[LEFT][first_singuar_point_next->pos.v].push_back(std::make_pair(first_singuar_point_next, Direct::right));
            period_edge_u[RIGHT][second_singuar_point_next->pos.v].push_back(std::make_pair(second_singuar_point_next, Direct::right));
        }
    }
}

void LoopProcessor::ProcessSingularPoints(PPointPtr start) {
    PPointPtr prev = start;
    do {
        if (prev->GetNext() == nullptr || prev->GetNext()->GetNext() == nullptr) return;
        PPointPtr curr = prev->GetNext();
        PPointPtr next = curr->GetNext();
        if (boundary_analyzer_.IsSingular(curr->pos) && !boundary_analyzer_.IsSingular(next->pos) && !boundary_analyzer_.IsSingular(prev->pos)) {
            auto prev_dir = boundary_analyzer_.GetClosestPoint(prev->pos, curr->pos) - prev->pos;
            auto curr_dir = boundary_analyzer_.GetClosestPoint(curr->pos, next->pos) - curr->pos;
            double neg = prev_dir * curr_dir;
            if (!has_periphery && ((std::fabs(prev->pos.u - next->pos.u) > info_.u_tolerance && info_.is_periodic_u) || (std::fabs(prev->pos.v - next->pos.v) > info_.v_tolerance && info_.is_periodic_v))) neg = -neg;
            if (neg < 0) {
                auto ty = boundary_analyzer_.GetSingularType(curr->pos);
                switch (ty) {
                case bndy_low_u:
                case bndy_high_u:
                    HandleCrossSingularPoint<ParamDirect::U>(prev, curr, next);
                    break;
                case bndy_low_v:
                case bndy_high_v:
                    HandleCrossSingularPoint<ParamDirect::V>(prev, curr, next);
                    break;
                }
                break;
            }
            else if (singularity_generator_ != nullptr) {
                PPointPtr& first_singuar_point = curr;
                PPointPtr second_singuar_point = std::make_shared<PPoint>(*first_singuar_point);
                if (auto next_locked = next) {  // 直接使用已解锁的 next
                    second_singuar_point->SetNext(next_locked);
                }
                else {
                    second_singuar_point->SetNext(nullptr);  // 如果 next 无效，设为 nullptr
                }
                first_singuar_point->SetNext(second_singuar_point);
                auto ty = boundary_analyzer_.GetSingularType(first_singuar_point->pos);
                switch (ty) {
                case bndy_low_u:
                case bndy_high_u:
                    first_singuar_point->pos.v = prev->pos.v;
                    second_singuar_point->pos.v = next->pos.v;
                    break;
                case bndy_low_v:
                case bndy_high_v:
                    first_singuar_point->pos.u = prev->pos.u;
                    second_singuar_point->pos.u = next->pos.u;
                    break;
                }
                ConnectTwoPointByGenerator(first_singuar_point, second_singuar_point, singularity_generator_);
                ppoint_set_.insert(second_singuar_point);
            }
        }
        prev = curr;
    } while (prev != nullptr && prev != start);
}

template <ParamDirect X> std::vector<PPointPtr> LoopProcessor::LoopSplit(std::array<std::map<double, std::vector<std::pair<PPointPtr, Direct>>>, 2>& period_edge, PPointPtr start) {
    std::vector<PPointPtr> segments{ start };
    PPointPtr prev_point = start;
    PPointPtr curr_point{ nullptr };
    PPointPtr next_point{ nullptr };
    // TODO: 一段式做法
    // 两段式做法
    while (auto next_locked = prev_point->GetNext()) {  // 解锁 prev_point->GetNext()
        curr_point = next_locked;                      // 获取当前点

        if (auto next_locked2 = curr_point->GetNext()) {  // 解锁 curr_point->GetNext()
            next_point = next_locked2;                   // 获取下一个点
        }
        else {
            break;  // 如果下一个点无效，跳出循环
        }
        if (boundary_analyzer_.IsSingular(curr_point->pos)) {
            prev_point = curr_point;
            if (prev_point == start) break;
            continue;
        }
        double cord;
        if constexpr (X == ParamDirect::U) {
            cord = curr_point->pos.v;
        }
        else {
            cord = curr_point->pos.u;
        }

        if (boundary_analyzer_.IsOnBoundary<X>(curr_point->pos)) {
            Direct dir = boundary_analyzer_.GetDirectRelateBoundary<X>(SPApar_dir(curr_point->dir));
            Direct tmp_pos[2];
            if (boundary_analyzer_.IsOnBoundary<X>(next_point->pos)) {
                dir = static_cast<Direct>(GetIndex(dir) ^ 1);
            }
            if (dir == Direct::right) {
                if constexpr (X == ParamDirect::U) {
                    curr_point->pos.u = info_.u_le;
                }
                else {
                    curr_point->pos.v = info_.v_ri;
                }
            }
            else {
                if constexpr (X == ParamDirect::U) {
                    curr_point->pos.u = info_.u_ri;
                }
                else {
                    curr_point->pos.v = info_.v_le;
                }
            }
            tmp_pos[0] = dir;

            PPointPtr copy_point = std::make_shared<PPoint>(*curr_point);
            copy_point->SetNext(nullptr);
            dir = boundary_analyzer_.GetDirectRelateBoundary<X>(SPApar_dir(prev_point->dir));
            if (dir == Direct::left) {
                if constexpr (X == ParamDirect::U) {
                    copy_point->pos.u = info_.u_le;
                }
                else {
                    copy_point->pos.v = info_.v_ri;
                }
            }
            else {
                if constexpr (X == ParamDirect::U) {
                    copy_point->pos.u = info_.u_ri;
                }
                else {
                    copy_point->pos.v = info_.v_le;
                }
            }
            tmp_pos[1] = static_cast<Direct>(GetIndex(dir) ^ 1);
            if (tmp_pos[0] != tmp_pos[1]) {
                period_edge[GetIndex(tmp_pos[0])][cord].push_back((std::make_pair(curr_point, tmp_pos[0])));
                period_edge[GetIndex(tmp_pos[1])][cord].push_back((std::make_pair(copy_point, dir)));
                ppoint_set_.insert(copy_point);
                prev_point->SetNext(copy_point);
                segments.push_back(curr_point);
            }
        }
        prev_point = curr_point;
        if (prev_point == start) break;
    }
    return segments;
}

template <ParamDirect X> void LoopProcessor::LoopsConnect(std::array<std::map<double, std::vector<std::pair<PPointPtr, Direct>>>, 2>& period_edge) {
    // 连接点
    std::vector<PPointPtr> error_point[2];
    for (int i = 0; i < 2; i++) {
        auto& side = period_edge[i];
        std::queue<std::pair<PPointPtr, Direct>> need_connect_points;
        // U direction from small to large connection, V direction from large to small connection
        if (i == 0) {
            for (auto& [cord, vec_pair] : side) {
                for (int j = 0; j < vec_pair.size(); j++) {  // The reason to merge first is to deal with the ring degenerating into an edge
                    if (j < static_cast<int>(vec_pair.size()) - 1 && GetIndex(vec_pair[j].second) != i && GetIndex(vec_pair[j + 1].second) == i) {
                        ConnectTwoPointByGenerator(vec_pair[j].first, vec_pair[j + 1].first, generator_);
                        j++;
                        continue;
                    }
                    else {
                        need_connect_points.push(vec_pair[j]);
                    }
                }
            }
        }
        else {
            for (auto it = side.rbegin(); it != side.rend(); ++it) {
                auto& vec_pair = it->second;
                for (int j = static_cast<int>(vec_pair.size()) - 1; j >= 0; j--) {
                    if (j > 0 && GetIndex(vec_pair[j].second) != i && GetIndex(vec_pair[j - 1].second) == i) {
                        ConnectTwoPointByGenerator(vec_pair[j].first, vec_pair[j - 1].first, generator_);
                        j--;
                        continue;
                    }
                    else {
                        need_connect_points.push(vec_pair[j]);
                    }
                }
            }
        }
        if (need_connect_points.size() >= 2 && !has_periphery) {  // Handle the boundaries added by yourself separately.
            auto one = need_connect_points.front();
            need_connect_points.pop();
            auto two = need_connect_points.front();
            if (one.second != two.second) {
                ConnectTwoPointByGenerator(one.first, two.first, generator_);
                need_connect_points.pop();
            }
        }
        if (!need_connect_points.empty() && GetIndex(need_connect_points.front().second) == i) {
            error_point[i].push_back(need_connect_points.front().first);
            need_connect_points.pop();
        }
        while (need_connect_points.size() >= 2) {
            auto one = need_connect_points.front();
            need_connect_points.pop();
            auto two = need_connect_points.front();
            if (one.second == two.second) {
                continue;
            }
            ConnectTwoPointByGenerator(one.first, two.first, generator_);
            need_connect_points.pop();
        }
        if (need_connect_points.size() == 1 && GetIndex(need_connect_points.front().second) != i) {
            error_point[i].push_back(need_connect_points.front().first);
        }
    }
    if (error_point[0].size() != error_point[1].size()) {
        return;
    }
    for (int i = 0; i < error_point[0].size(); i++) {
        auto one = error_point[0][i];
        auto two = error_point[1][i];
        if (one->GetNext() == nullptr && two->GetNext()) {
            one->SetNext(two);
        }
        else if (one->GetNext() && two->GetNext() == nullptr) {
            two->SetNext(one);
        }
    }
    return;
}

void LoopProcessor::ConnectTwoPointByGenerator(PPointPtr begin, PPointPtr end, std::function<std::vector<SPApar_pos>(SPApar_pos, SPApar_pos)> generator) {
    std::vector<SPApar_pos> tmp = generator_(begin->pos, end->pos);
    PPointPtr last = begin;
    for (auto& tmp_point : tmp) {
        PPointPtr tmp_ppoint = std::make_shared<PPoint>(tmp_point);
        ppoint_set_.insert(tmp_ppoint);
        last->SetNext(tmp_ppoint);
        last = tmp_ppoint;
    }
    last->SetNext(end);
}

PPointPtr LoopProcessor::GetDiscreteLoop(LOOP* lp) {
    std::vector<point_vector> loop;
    unsigned ic = 0;
    PPointPtr begin = nullptr;       // Loop的第一个点
    PPointPtr last_point = nullptr;  // 每个coedge最后一个点
    bool has_singular{ false };
    for (COEDGE* coedge = lp->start(); coedge != lp->start() || ic == 0; coedge = info_.sense ^ info_.surf.left_handed_uv() ? coedge->previous() : coedge->next(), ic++) {
        if (IsEdgeDegenerate(coedge->edge())) {
            continue;
        }
        auto result = GetPPointsFromCoedge(coedge);
        if (result.start == nullptr) continue;
        if (begin == nullptr) {
            begin = result.start;
        }
        has_singular |= result.has_singular;
        if (last_point != nullptr) {  // 如果相同，则删除当前coedge的第一个ppoint再连接
            ppoint_set_.erase(result.start);
            last_point->SetNext(result.start->GetNext());
        }
        last_point = result.end;
    }

    if (begin == nullptr) {
        return nullptr;
    }
    // Loop的最后一个点和第一个点相同，去掉最后一个点，连接形成环
    last_point->SetNext(begin->GetNext());
    ppoint_set_.erase(begin);
    begin = last_point;

    begin = PPointsFilter(begin);
    begin = PPointsFixer(begin);

#ifdef DEBUG
    int cnt = 0;
    PPointPtr test_point = begin;
    do {
        cnt++;
        std::cout << test_point->pos.u << ' ' << test_point->pos.v << std::endl;
        test_point = test_point->GetNext();
    } while (test_point && test_point != begin);
    std::cout << "###############\n";

#endif  // DEBUG

    return begin;
}

LoopProcessor::LoopProcessor(FACE* _face) : boundary_analyzer_(_face), info_(_face) {
    api_get_loops(_face, face_loops_);
    generator_ = [](SPApar_pos first, SPApar_pos end) { return std::vector<SPApar_pos>(); };
    Box box = Box{
      {info_.u_le, info_.v_le},
      {info_.u_ri, info_.v_ri}
    };
    corner_ppoints = { std::make_shared<PPoint>(box.getBotLeft()), std::make_shared<PPoint>(box.getTopLeft()), std::make_shared<PPoint>(box.getTopRight()), std::make_shared<PPoint>(box.getBotRight()) };
    // 非周期必定有边界约束，不添加边界
    if (info_.is_periodic_u || info_.is_periodic_v) {
        ppoint_set_.insert(corner_ppoints.bot_left);
        ppoint_set_.insert(corner_ppoints.top_left);
        ppoint_set_.insert(corner_ppoints.top_right);
        ppoint_set_.insert(corner_ppoints.bot_right);
    }
}

void LoopProcessor::Execute() {
    for (auto item : face_loops_) {
        auto lp = static_cast<LOOP*>(item);
        loop_type ty;
        api_loop_type(lp, ty);
        has_periphery |= ty == loop_periphery;
    }
    // 特殊处理无边
    if (!has_periphery) {
        period_edge_u[LEFT][info_.v_le].push_back(std::make_pair(corner_ppoints.bot_right, Direct::right));
        period_edge_u[RIGHT][info_.v_le].push_back(std::make_pair(corner_ppoints.bot_left, Direct::right));
        period_edge_v[LEFT][info_.u_le].push_back(std::make_pair(corner_ppoints.bot_left, Direct::right));
        period_edge_v[RIGHT][info_.u_le].push_back(std::make_pair(corner_ppoints.top_left, Direct::right));
    }
    for (auto item : face_loops_) {
        auto lp = static_cast<LOOP*>(item);
        PPointPtr begin = GetDiscreteLoop(lp);
        loop_type ty;
        api_loop_type(lp, ty);
        if (ty == loop_type::loop_periphery) {
            no_boundary = false;
        }
        if (begin == nullptr || begin->GetNext() == nullptr) continue;
        std::vector<PPointPtr> segments{ begin };
        // The following method cannot handle crossing corners that happen to be on the boundary of a double period
        if (info_.is_periodic_u) {
            segments = LoopSplit<ParamDirect::U>(period_edge_u, begin);
        }
        if (info_.is_periodic_v) {
            auto tmp = std::move(segments);
            for (auto& x : tmp) {
                auto res = LoopSplit<ParamDirect::V>(period_edge_v, x);
                segments.insert(segments.end(), res.begin(), res.end());
            }
        }
        for (auto start : segments) {
            ProcessSingularPoints(start);
        }
    }
    if (!has_periphery) {
        period_edge_u[RIGHT][info_.v_ri].push_back(std::make_pair(corner_ppoints.top_left, Direct::left));
        period_edge_u[LEFT][info_.v_ri].push_back(std::make_pair(corner_ppoints.top_right, Direct::left));
        period_edge_v[LEFT][info_.u_ri].push_back(std::make_pair(corner_ppoints.bot_right, Direct::left));
        period_edge_v[RIGHT][info_.u_ri].push_back(std::make_pair(corner_ppoints.top_right, Direct::left));
    }
    LoopsConnect<ParamDirect::U>(period_edge_u);
    LoopsConnect<ParamDirect::V>(period_edge_v);
    Extract();
}

void LoopProcessor::Extract() {
    std::unordered_set<PPointPtr> mark;
    // 存有全局的Loop折线段上的点
    std::vector<SPApar_pos> _points;
    // 每个std::vector是一个loop折线的索引数组
    std::vector<std::vector<int>> _idx_loops;
    int idx = 0;
    // 从 ppoint_set_ 中提取折线段
    for (auto& x : ppoint_set_) {
        std::vector<SPApar_pos> segment_points;
        PPointPtr p = x;
        while (p) {
            if (mark.find(p) != mark.end()) {
                std::vector<int> idx_loop;
                if (p == x && segment_points.size() > 1) {
                    for (auto& point : segment_points) {
                        _points.push_back(point);
                        idx_loop.push_back(idx);
                        idx++;
                    }
                    _idx_loops.push_back(std::move(idx_loop));
                }
                break;
            }
            mark.insert(p);
            segment_points.emplace_back(p->pos.u, p->pos.v);
            p = p->GetNext();
        }
    }
    enum class TYPE { UP, DOWN };
    std::vector<std::pair<int, TYPE>> period_edge[2];
    // 分别将周期边界上的点加入数据结构中
    if (info_.is_periodic_u || info_.is_periodic_v) {
        for (int i = 0; i < _points.size(); i++) {
            auto boundary_type = boundary_analyzer_.GetBoundaryType(_points[i]);
            if (info_.is_periodic_u) {
                if (boundary_type == bndy_low_u) {
                    period_edge[0].emplace_back(std::make_pair(i, TYPE::UP));
                }
                else if (boundary_type == bndy_high_u) {
                    period_edge[0].emplace_back(std::make_pair(i, TYPE::DOWN));
                }
            }
            else {
                if (boundary_type == bndy_low_v) {
                    period_edge[1].emplace_back(std::make_pair(i, TYPE::UP));
                }
                else if (boundary_type == bndy_high_v) {
                    period_edge[1].emplace_back(std::make_pair(i, TYPE::DOWN));
                }
            }
        }
    }
    std::sort(period_edge[0].begin(), period_edge[0].end(), [&](std::pair<int, TYPE>& a, std::pair<int, TYPE>& b) { return _points[a.first].v < _points[b.first].v; });
    std::sort(period_edge[1].begin(), period_edge[1].end(), [&](std::pair<int, TYPE>& a, std::pair<int, TYPE>& b) { return _points[a.first].u < _points[b.first].u; });
    std::vector<int> rehash(_points.size());
    std::iota(rehash.begin(), rehash.end(), 0);
    // 周期边界上的点去重
    for (int op = 0; op < 2; op++) {
        if ((op == 0 && info_.is_periodic_u) || (op == 1 && info_.is_periodic_v)) {
            for (int i = 1; i < period_edge[op].size(); i++) {
                auto& p1 = _points[period_edge[op][i - 1].first], & p2 = _points[period_edge[op][i].first];
                if (boundary_analyzer_.SamePointJudgeBy3D(p1, p2) && period_edge[op][i - 1].second != period_edge[op][i].second) {
                    rehash[period_edge[op][i].first] = rehash[period_edge[op][i - 1].first];
                }
            }
        }
    }
    points = std::move(_points);
    loops_indexs = std::move(_idx_loops);
    points_mapping = std::move(rehash);
}